#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
文件服务器 - 支持文件上传和下载，包含元数据管理
作者: AI Assistant
"""

import os
import json
import uuid
from datetime import datetime
from flask import Flask, request, jsonify, send_file, send_from_directory
from flask_cors import CORS
from werkzeug.utils import secure_filename
# from werkzeug.exceptions import RequestEntityTooLarge  # 已取消文件大小限制，不再需要此异常
import mimetypes

app = Flask(__name__)
CORS(app)  # 启用CORS支持

# 配置
UPLOAD_FOLDER = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'assets')
# MAX_CONTENT_LENGTH = 16 * 1024 * 1024  # 16MB 最大文件大小 - 已取消大小限制
ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif', 'doc', 'docx', 'zip', 'rar', 'mp3', 'mp4', 'avi'}
PREVIEW_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif', 'webp'}

app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
# app.config['MAX_CONTENT_LENGTH'] = MAX_CONTENT_LENGTH  # 已取消文件上传大小限制

# 确保上传目录存在
os.makedirs(UPLOAD_FOLDER, exist_ok=True)

# JSON数据库文件路径
FILES_DB_PATH = os.path.join(UPLOAD_FOLDER, 'files_metadata.json')

def allowed_file(filename):
    """检查文件扩展名是否被允许 - 已修改为允许所有文件类型"""
    return True  # 允许上传任意类型的文件

def allowed_preview_file(filename):
    """检查预览图文件扩展名是否被允许"""
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in PREVIEW_EXTENSIONS

def get_file_info(filepath):
    """获取文件信息"""
    stat = os.stat(filepath)
    
    # 获取文件扩展名作为类型
    filename = os.path.basename(filepath)
    if '.' in filename:
        file_type = filename.rsplit('.', 1)[1].lower()
    else:
        file_type = 'unknown'
    
    return {
        'size': stat.st_size,
        'modified': datetime.fromtimestamp(stat.st_mtime).strftime('%Y-%m-%d %H:%M:%S'),
        'type': file_type
    }

def load_files_db():
    """加载文件数据库"""
    if os.path.exists(FILES_DB_PATH):
        try:
            with open(FILES_DB_PATH, 'r', encoding='utf-8') as f:
                return json.load(f)
        except (json.JSONDecodeError, IOError):
            return {}
    return {}

def save_files_db(data):
    """保存文件数据库"""
    try:
        with open(FILES_DB_PATH, 'w', encoding='utf-8') as f:
            json.dump(data, f, ensure_ascii=False, indent=2)
        return True
    except IOError:
        return False

def add_file_to_db(file_id, file_data):
    """添加文件到数据库"""
    db = load_files_db()
    db[file_id] = file_data
    return save_files_db(db)

def remove_file_from_db(file_id):
    """从数据库中移除文件"""
    db = load_files_db()
    if file_id in db:
        del db[file_id]
        return save_files_db(db)
    return False

def get_file_from_db(file_id):
    """从数据库获取文件信息"""
    try:
        with open(FILES_DB_PATH, 'r', encoding='utf-8') as f:
            data = json.load(f)
        file_data = data.get(file_id)
        
        # 修复display_name没有扩展名的问题（仅在内存中修复，不立即写入数据库）
        if file_data and file_data.get('display_name'):
            display_name = file_data['display_name']
            original_name = file_data.get('original_name', '')
            
            # 如果display_name没有扩展名，但original_name有扩展名
            if not os.path.splitext(display_name)[1] and os.path.splitext(original_name)[1]:
                file_ext = os.path.splitext(original_name)[1]
                file_data = file_data.copy()  # 创建副本避免修改原数据
                file_data['display_name'] = display_name + file_ext
        
        return file_data
    except (FileNotFoundError, json.JSONDecodeError):
        return None

# 配置 dist 文件夹路径
DIST_FOLDER = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'dist')

@app.route('/')
def index():
    """主页面 - 返回 Vue 打包后的 index.html"""
    try:
        return send_from_directory(DIST_FOLDER, 'index.html')
    except FileNotFoundError:
        return jsonify({'error': 'Vue 应用未找到，请先运行 npm run build'}), 404

@app.route('/<path:filename>')
def static_files(filename):
    """静态文件服务 - 提供 dist 文件夹中的静态资源"""
    try:
        return send_from_directory(DIST_FOLDER, filename)
    except FileNotFoundError:
        return jsonify({'error': '文件未找到'}), 404

@app.route('/upload', methods=['POST'])
def upload_files():
    """文件上传接口 - 支持文件、预览图、标签等元数据"""
    try:
        if 'files' not in request.files:
            return jsonify({'error': '没有选择文件'}), 400
        
        files = request.files.getlist('files')
        previews = request.files.getlist('previews')
        custom_name = request.form.get('custom_name', '').strip()
        tags_str = request.form.get('tags', '').strip()
        description = request.form.get('description', '').strip()
        
        if not files or all(file.filename == '' for file in files):
            return jsonify({'error': '没有选择文件'}), 400
        
        # 处理标签
        tags = [tag.strip() for tag in tags_str.split(',') if tag.strip()] if tags_str else []
        
        uploaded_files = []
        failed_files = []
        
        for i, file in enumerate(files):
            if file and file.filename != '':
                if allowed_file(file.filename):
                    # 生成唯一文件ID
                    file_id = str(uuid.uuid4())
                    
                    # 处理文件名
                    original_filename = file.filename  # 保存原始文件名（包含扩展名）
                    safe_filename = secure_filename(file.filename)  # 安全的文件名用于处理
                    file_ext = os.path.splitext(original_filename)[1]  # 从原始文件名获取扩展名
                    
                    if custom_name and len(files) == 1:
                        # 如果自定义名称没有扩展名，添加原文件的扩展名
                        if not os.path.splitext(custom_name)[1]:
                            display_name = custom_name + file_ext
                        else:
                            display_name = custom_name
                    else:
                        display_name = original_filename
                    
                    # 保存主文件
                    stored_filename = f"{file_id}{file_ext}"
                    filepath = os.path.join(app.config['UPLOAD_FOLDER'], stored_filename)
                    file.save(filepath)
                    
                    # 处理预览图
                    preview_filename = None
                    if i < len(previews) and previews[i].filename != '':
                        preview_file = previews[i]
                        if allowed_preview_file(preview_file.filename):
                            preview_ext = os.path.splitext(preview_file.filename)[1]
                            preview_filename = f"{file_id}_preview{preview_ext}"
                            preview_path = os.path.join(app.config['UPLOAD_FOLDER'], preview_filename)
                            preview_file.save(preview_path)
                    
                    # 获取文件信息
                    file_info = get_file_info(filepath)
                    
                    # 创建文件元数据
                    file_data = {
                        'id': file_id,
                        'original_name': original_filename,
                        'display_name': display_name,
                        'file_path': stored_filename,
                        'preview_url': preview_filename,
                        'size': file_info['size'],
                        'type': file_info['type'],
                        'tags': tags,
                        'description': description,
                        'upload_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
                        'modified': file_info['modified']
                    }
                    
                    # 保存到数据库
                    if add_file_to_db(file_id, file_data):
                        uploaded_files.append(display_name)
                    else:
                        failed_files.append(f"{display_name} (数据库保存失败)")
                        # 清理已上传的文件
                        if os.path.exists(filepath):
                            os.remove(filepath)
                        if preview_filename and os.path.exists(os.path.join(app.config['UPLOAD_FOLDER'], preview_filename)):
                            os.remove(os.path.join(app.config['UPLOAD_FOLDER'], preview_filename))
                else:
                    failed_files.append(f"{file.filename} (不支持的文件类型)")
        
        message = f"成功上传 {len(uploaded_files)} 个文件"
        if failed_files:
            message += f"，{len(failed_files)} 个文件失败"
        
        return jsonify({
            'success': True,
            'message': message,
            'uploaded': uploaded_files,
            'failed': failed_files
        })
        
    # except RequestEntityTooLarge:  # 已取消文件大小限制，不再需要此异常处理
    #     return jsonify({'error': '文件太大，最大支持16MB'}), 413
    except Exception as e:
        return jsonify({'error': f'上传失败: {str(e)}'}), 500

@app.route('/files', methods=['GET'])
def list_files():
    """获取文件列表 - 从JSON数据库获取完整文件信息"""
    try:
        files_db = load_files_db()
        files_list = []
        
        for file_id, _ in files_db.items():
            # 使用get_file_from_db来触发自动修复
            file_data = get_file_from_db(file_id)
            if not file_data:
                continue
                
            # 检查文件是否仍然存在
            file_path = os.path.join(app.config['UPLOAD_FOLDER'], file_data['file_path'])
            if os.path.exists(file_path):
                # 构建预览图URL
                preview_url = None
                if file_data.get('preview_url'):
                    preview_url = file_data['preview_url']
                
                files_list.append({
                    'id': file_id,
                    'name': file_data['file_path'],
                    'display_name': file_data['display_name'],
                    'original_name': file_data['original_name'],
                    'file_path': file_data['file_path'],
                    'size': file_data['size'],
                    'type': file_data['type'],
                    'tags': file_data.get('tags', []),
                    'description': file_data.get('description', ''),
                    'upload_time': file_data['upload_time'],
                    'modified': file_data['modified'],
                    'preview_url': preview_url
                })
            else:
                # 如果文件不存在，从数据库中移除
                remove_file_from_db(file_id)
        
        # 按上传时间排序
        files_list.sort(key=lambda x: x['upload_time'], reverse=True)
        
        return jsonify({'files': files_list})
    except Exception as e:
        return jsonify({'error': f'获取文件列表失败: {str(e)}'}), 500

@app.route('/download/<file_id>')
def download_file(file_id):
    """文件下载接口 - 通过文件ID下载"""
    try:
        file_data = get_file_from_db(file_id)
        if not file_data:
            return jsonify({'error': '文件不存在'}), 404
        
        file_path = os.path.join(app.config['UPLOAD_FOLDER'], file_data['file_path'])
        if not os.path.exists(file_path):
            # 文件不存在，从数据库中移除
            remove_file_from_db(file_id)
            return jsonify({'error': '文件不存在'}), 404
        
        return send_file(
            file_path, 
            as_attachment=True,
            download_name=file_data['display_name']
        )
    except Exception as e:
        return jsonify({'error': f'下载失败: {str(e)}'}), 500

@app.route('/preview/<filename>')
def preview_file(filename):
    """预览图接口"""
    try:
        filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
        if not os.path.exists(filepath):
            return jsonify({'error': '预览图不存在'}), 404
        
        return send_file(filepath)
    except Exception as e:
        return jsonify({'error': f'获取预览图失败: {str(e)}'}), 500

@app.route('/delete/<file_id>', methods=['DELETE'])
def delete_file(file_id):
    """文件删除接口 - 通过文件ID删除"""
    try:
        file_data = get_file_from_db(file_id)
        if not file_data:
            return jsonify({'error': '文件不存在'}), 404
        
        # 删除主文件
        file_path = os.path.join(app.config['UPLOAD_FOLDER'], file_data['file_path'])
        if os.path.exists(file_path):
            os.remove(file_path)
        
        # 删除预览图
        if file_data.get('preview_url'):
            preview_path = os.path.join(app.config['UPLOAD_FOLDER'], file_data['preview_url'])
            if os.path.exists(preview_path):
                os.remove(preview_path)
        
        # 从数据库中移除
        if remove_file_from_db(file_id):
            return jsonify({'success': True, 'message': f'文件 {file_data["display_name"]} 删除成功'})
        else:
            return jsonify({'error': '从数据库删除失败'}), 500
            
    except Exception as e:
        return jsonify({'error': f'删除失败: {str(e)}'}), 500

@app.route('/info')
def server_info():
    """服务器信息接口"""
    try:
        total_files = len([f for f in os.listdir(app.config['UPLOAD_FOLDER']) 
                          if os.path.isfile(os.path.join(app.config['UPLOAD_FOLDER'], f))])
        
        total_size = sum(os.path.getsize(os.path.join(app.config['UPLOAD_FOLDER'], f))
                        for f in os.listdir(app.config['UPLOAD_FOLDER'])
                        if os.path.isfile(os.path.join(app.config['UPLOAD_FOLDER'], f)))
        
        return jsonify({
            'upload_folder': app.config['UPLOAD_FOLDER'],
            'max_file_size': app.config['MAX_CONTENT_LENGTH'],
            'allowed_extensions': list(ALLOWED_EXTENSIONS),
            'total_files': total_files,
            'total_size': total_size
        })
    except Exception as e:
        return jsonify({'error': f'获取服务器信息失败: {str(e)}'}), 500

@app.errorhandler(413)
def too_large(e):
    return jsonify({'error': '文件太大，最大支持16MB'}), 413

@app.errorhandler(404)
def not_found(e):
    return jsonify({'error': '页面不存在'}), 404

@app.errorhandler(500)
def internal_error(e):
    return jsonify({'error': '服务器内部错误'}), 500

if __name__ == '__main__':
    print(f"文件服务器启动中...")
    print(f"上传目录: {UPLOAD_FOLDER}")
    print(f"最大文件大小: 无限制")
    print(f"支持的文件类型: {', '.join(ALLOWED_EXTENSIONS)}")
    print(f"访问地址: http://localhost:5000")
    
    app.run(host='0.0.0.0', port=5000, debug=True)